﻿/*
 * Callback.h
 */

#ifndef __GDK_CALLBACK_H__
#define __GDK_CALLBACK_H__


#include <gdk/core/Types.h>
#include <gdk/core/Unknown.h>
#include <gdk/core/SharedPtr.h>
#include <gdk/core/String.h>


namespace gdk
{


	template<typename TyReturn, typename TyBaseParameter>
	class CallbackBase : virtual public Unknown
	{
		DECLARE_CLASS_HANDLE(CallbackBase)

	public:
		virtual TyReturn operator()(TyBaseParameter) const = 0;
		virtual String toString(void) const = 0;

		bool operator==(CallbackBase<TyReturn, TyBaseParameter> const &o) const
		{
			return (toString() == o.toString());
		}
		__INLINE__ bool operator!=(CallbackBase<TyReturn, TyBaseParameter> const &o) const
		{
			return !(this->operator ==(o));
		}
		bool operator<(CallbackBase<TyReturn, TyBaseParameter> const &o) const
		{
			return (toString() < o.toString());
		}
		bool operator>(CallbackBase<TyReturn, TyBaseParameter> const &o) const
		{
			return (toString() > o.toString());
		}
		__INLINE__ bool operator<= (CallbackBase<TyReturn, TyBaseParameter> const &o) const
		{
			return !(this->operator >(o));
		}
		__INLINE__ bool operator>=(CallbackBase<TyReturn, TyBaseParameter> const &o) const
		{
			return !(this->operator <(o));
		}
	};



	template<	typename TyReturn,
				typename TyBaseParameter,
				typename TyClass,
				typename TyParameter=TyBaseParameter
	>
	class CallbackClass : public CallbackBase<TyReturn, TyBaseParameter>
	{
	public:
		typedef TyReturn (TyClass::*TyFunction)(TyParameter);

	public:
		DECLARE_CLASS_HANDLE(CallbackClass)
		DECLARE_CLASS_INSTANCE2(CallbackClass, TyClass*, TyFunction)
		DECLARE_CLASS_INSTANCE2(CallbackClass, gdk::Unknown::Handle_T<TyClass> const &, TyFunction)

	private:
		String mutable					_key;
		gdk::Unknown::Handle_T<TyClass>	_obj;
		union {
		TyFunction						_func;
		void*							_func_ptr;
		};


	protected:
		__INLINE__ CallbackClass(TyClass *obj, TyFunction func)
			: _obj(obj)
			, _func(func)
		{
		}

		__INLINE__ CallbackClass(gdk::Unknown::Handle_T<TyClass> const &obj, TyFunction func)
			: _obj(obj)
			, _func(func)
		{
		}

	public:
		virtual TyReturn operator()(TyBaseParameter param) const
		{
			return (_obj->*_func)(static_cast<TyParameter>(param));
		}
		virtual String toString(void) const
		{
			if (_key.empty())
			{
				_key.format(__TEXT__("%p@%p"), (const TyClass*)_obj, _func_ptr);
			}
			return _key;
		}
	};



	template<	typename TyReturn,
				typename TyBaseParameter,
				typename TyClass,
				typename TyParameter=TyBaseParameter
	>
	class CallbackSharedClass : public CallbackBase<TyReturn, TyBaseParameter>
	{
	public:
		typedef TyReturn (TyClass::*TyFunction)(TyParameter);

	public:
		DECLARE_CLASS_HANDLE(CallbackSharedClass)
		DECLARE_CLASS_INSTANCE2(CallbackSharedClass, SharedPtr<TyClass> const &, TyFunction)

	private:
		String mutable		_key;
		SharedPtr<TyClass>	_obj;
		union {
		TyFunction			_func;
		void*				_func_ptr;
		};

	protected:
		__INLINE__ CallbackSharedClass(SharedPtr<TyClass> const &obj, TyFunction func)
			: _obj(obj)
			, _func(func)
		{
		}

	public:
		virtual TyReturn operator()(TyBaseParameter param) const
		{
			return (_obj->*_func)(static_cast<TyParameter>(param));
		}
		virtual String toString(void) const
		{
			if (_key.empty())
			{
				_key.format(__TEXT__("%p@%p"), (const TyClass*)_obj, _func_ptr);
			}
			return _key;
		}
	};


	template<	typename TyReturn,
				typename TyBaseParameter,
				typename TyClass,
				typename TyParameter=TyBaseParameter
	>
	class CallbackClassReference : public CallbackBase<TyReturn, TyBaseParameter>
	{
	public:
		typedef TyReturn (TyClass::*TyFunction)(TyParameter);

	public:
		DECLARE_CLASS_HANDLE(CallbackClassReference)
		DECLARE_CLASS_INSTANCE2(CallbackClassReference, TyClass&, TyFunction)

	private:
		String mutable	_key;
		TyClass*		_obj;
		union {
		TyFunction		_func;
		void*			_func_ptr;
		};

	protected:
		__INLINE__ CallbackClassReference(TyClass &obj, TyFunction func)
			: _obj(&obj)
			, _func(func)
		{
		}

	public:
		virtual TyReturn operator()(TyBaseParameter param) const
		{
			return (_obj->*_func)(static_cast<TyParameter>(param));
		}
		virtual String toString(void) const
		{
			if (_key.empty())
			{
				_key.format(__TEXT__("%p@%p"), _obj, _func_ptr);
			}
			return _key;
		}
	};


	template<	typename TyReturn,
				typename TyBaseParameter,
				typename TyParameter=TyBaseParameter
	>
	class CallbackFunction : public CallbackBase<TyReturn, TyBaseParameter>
	{
	public:
		typedef TyReturn (*TyFunction)(TyParameter);

	public:
		DECLARE_CLASS_HANDLE(CallbackFunction)
		DECLARE_CLASS_INSTANCE1(CallbackFunction, TyFunction)

	public:
		TyFunction		_func;
		String mutable	_key;

	protected:
		__INLINE__ CallbackFunction(TyFunction func)
			: _func(func)
		{
		}

	public:
		virtual TyReturn operator()(TyBaseParameter param) const
		{
			return (_func)(static_cast<TyParameter>(param));
		}
		virtual String toString(void) const
		{
			if (_key.empty())
			{
				_key.format(__TEXT__("%p"), _func);
			}
			return _key;
		}
	};



	template<typename TyReturn, typename TyBaseParameter>
	class CallbackHandler
	{
	public:
		typedef typename gdk::CallbackBase<TyReturn, TyBaseParameter>	CallbackBase;
		typedef typename gdk::Unknown::Handle_T<CallbackBase>			Callback;

	private:
		Callback	_callback;

	public:
		__INLINE__ CallbackHandler(void)
		{
		}

		__INLINE__ CallbackHandler(CallbackHandler const &o)
			: _callback(o._callback)
		{
		}

		__INLINE__ CallbackHandler(Callback const &callback)
			: _callback(callback)
		{
		}

		bool operator==(CallbackHandler const &o) const
		{
			return (toString() == o.toString());
		}
		__INLINE__ bool operator!=(CallbackHandler const &o) const
		{
			return !(this->operator ==(o));
		}
		bool operator<(CallbackHandler const &o) const
		{
			return (toString() < o.toString());
		}
		bool operator>(CallbackHandler const &o) const
		{
			return (toString() > o.toString());
		}
		__INLINE__ bool operator<=(CallbackHandler const &o) const
		{
			return !(this->operator >(o));
		}
		__INLINE__ bool operator>=(CallbackHandler const &o) const
		{
			return !(this->operator <(o));
		}

		__INLINE__ TyReturn operator()(TyBaseParameter param) const
		{
			return (*_callback)(param);
		}

		String toString(void) const
		{
			return (!isNull() ? _callback->toString() : __TEXT__(""));
		}

		__INLINE__ void setNull(void)
		{
			return _callback.setNull();
		}

		__INLINE__ bool isNull(void) const
		{
			return (_callback == NULL);
		}

		template<typename TyValue>
		CallbackHandler(TyReturn(*func)(TyValue))
			: _callback(CallbackFunction<
					TyReturn,
					TyBaseParameter,
					TyValue
				>::createInstance(func)
			)
		{
		}

		template<typename TyClass, typename TyValue>
		CallbackHandler(SharedPtr<TyClass> const &obj, TyReturn(TyClass::*func)(TyValue))
			: _callback(CallbackSharedClass<
					TyReturn,
					TyBaseParameter,
					TyClass,
					TyValue
				>::createInstance(obj, func)
			)
		{
		}

		template<typename TyClass, typename TyValue>
		CallbackHandler(TyClass *obj, TyReturn(TyClass::*func)(TyValue))
			: _callback(CallbackClassReference<
					TyReturn,
					TyBaseParameter,
					TyClass,
					TyValue
				>::createInstance(*obj, func)
			)
		{
		}

		template<typename TyClass, typename TyValue>
		CallbackHandler(gdk::Unknown::Handle_T<TyClass> const &obj, TyReturn(TyClass::*func)(TyValue))
			: _callback(CallbackClass<
					TyReturn,
					TyBaseParameter,
					TyClass,
					TyValue
				>::createInstance(obj, func)
			)
		{
		}

		template<typename TyClass, typename TyValue>
		CallbackHandler(TyClass &obj, TyReturn(TyClass::*func)(TyValue))
			: _callback(CallbackClassReference<
					TyReturn,
					TyBaseParameter,
					TyClass,
					TyValue
				>::createInstance(obj, func)
			)
		{
		}

	};




}//namespace gdk




#endif //__GDK_CALLBACK_H__
